#include <iostream>
#include <vector>
#include <unistd.h>
#include <signal.h>
using namespace std;

// 今天我们写一个关于屏蔽信号(阻塞信号)和解除信号屏蔽的代码

#define MAX_SIZE 31

static vector<int> block_sigset = { 1, 2, 3, 4, 5, 6, 7, 8, /*9,*/ 10, 11, 12, 13, 14, 15, 16, 17, /*18,*/ /*19,*/ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 };

static void show(const sigset_t &pending)
{
    cout << "当前进程pid : " << getpid() << " ;";
    for(int signo = MAX_SIZE; signo >= 1; signo--)
    {
        if(sigismember(&pending, signo) == 1)   // 在pending信号集中，表示收到该信号
            cout << "1";
        else
            cout << "0";
    }
    cout << "\n";
}

static void handler(int signo)
{
    cout << signo << " 号信号已经被递达!!!" << endl; 
}



int main()
{

    // 1.设置要屏蔽的信号
    sigset_t block, oldblock, pending;

    // 1.1初始化信号集
    sigemptyset(&block);
    sigemptyset(&oldblock);

    // 1.2设置对应信号编号进block中
    for(const auto& signo : block_sigset) sigaddset(&block, signo);

    // 1.3开始屏蔽信号,设置进内核(进程
    sigprocmask(SIG_SETMASK, &block, &oldblock);

    // 现在注册对所有要屏蔽的信号的自定义动作
    for(const auto& signo : block_sigset) signal(signo, handler);

    for(const auto& signo : block_sigset) kill(getpid(), signo);    // 向自己发送几乎所有信号(除了9，18，19)


    int cnt = 10;
    while(true)
    {
        // 2.获取pending信号集

        // 2.1初始化
        sigemptyset(&pending);

        // 2.2读取当前进程的未决信号集
        sigpending(&pending);

        // 2.3"打印"pending位图集
        show(pending);

        sleep(1);

        if(cnt-- == 0)
        {
            // 10s后恢复该信号(解除屏蔽)
            cout << "恢复对信号的屏蔽，不屏蔽任何信号\n";
            sigprocmask(SIG_SETMASK, &oldblock, &block);    // 一旦恢复了，且之前的pending信号集该信号比特位为1，恢复后就递达该信号了
            // 一旦对特定信号进行解除屏蔽，一般OS要至少立马递达一个信号！

            // 如果我们想要该信号递达之后继续被屏蔽，然后在10s之内继续恢复它这样的过程
            // 那么如下，继续屏蔽该信号
            sigprocmask(SIG_SETMASK, &block, &oldblock);
            cout << "再次屏蔽该信号成功\n";

            cnt = 10;   // 依然10s之后解除屏蔽

            for(const auto& signo : block_sigset) kill(getpid(), signo);    // 再次发送所有信号(除了9，18，19)

        }
    }

    return 0;
}